package com.cskaoyan.javase._0abstract._0introduction;

import javafx.animation.Animation;

/**
 * 抽象类的引入:
 * 以下猫狗继承案例，是一个非常基础的继承语法的代码。
 * 思考一下Animal类的继承体系，有什么问题吗？
 *
 * 从以下两个角度分析：
 * 从代码角度上，有没有冗余代码？
 * 从设计角度上，在这个案例中，会存在一个动物对象吗？
 *
 * 实际上,Animal类就是单纯为了继承的,不是为了创建对象的
 * 而且Animal类中的shout方法也不是为了被调用的,是为了让子类继承,被子类重写的
 * 而且Animal在本案例中是一个抽象的概念,本身就是描述全体动物的抽象,对于抽象概念,我们也不应该能够描述它的行为.
 * 综上，我们提出两个改进的方向：
 *      1.Animal类就是作为顶层抽象祖先类而存在的，不需要创建对象，于是干脆不要创建对象了。
 *      2.Animal类当中的shout方法不需要方法体，仅用于作为被继承和重写一个方法声明。
 *
 *
 * 1.如何声明抽象方法呢?
 * 语法:
 * [访问权限修饰符] abstract 返回值类型 方法名(形参列表);
 * 注: 抽象方法没有方法体,方法声明(方法头)后面要跟上";"
 * 抽象方法没有方法体,没有实现,且抽象方法处在抽象类中
 * 抽象类肯定不能创建对象,抽象方法也不可能直接调用
 * 所以抽象方法定义的目的就是为了让子类继承和重写的
 *
 * 抽象方法必须在抽象类中
 * 抽象类的定义语法：
 * [访问权限修饰符] abstract 类名{
 *     // 类体
 * }
 * 定义抽象类后，抽象类中可以定义抽象方法。
 * 注：抽象类无法new创建对象，抽象类是抽象的。
 * 抽象类一样,定义抽象类就是为了让子类继承的
 * 抽象类和它的子类仍然是继承(extends)关系
 * 抽象类是父类,其他普通类是子类
 * 存在父子类,也仍然存在多态现象.
 *
 * @since 09:34
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // 'Animal' is abstract; cannot be instantiated
        // new Animal();
        Animal a;
        a = new Cat();
        a.shout();
        a = new Dog();
        a.shout();
    }
}

abstract class Animal {
    /*
        加上abstract后:
            Abstract method in non-abstract class  抽象方法必须在抽象类中
            Class 'Animal' must either be declared abstract or implement abstract method 'shout()' in 'Animal'
                抽象类中才有抽象方法，普通类中没有抽象方法，普通类中都是（有方法体的）实现方法
      */
    // 加上分号后: Missing method body, or declare abstract 方法要么就有方法体,要么必须声明为抽象方法
    // 直接去掉大括号后: '{' or ';' expected
    public abstract void shout();
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("猫叫");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("狗叫");
    }
}